local CURRENT_MODULE = ...;
local dotindex = string.find(CURRENT_MODULE, "%.%w+$");
local currentpath = string.sub(CURRENT_MODULE, 1, dotindex-1);
local endPath = string.format("%s.%s", currentpath,"GridNode");
local GridNode = require(endPath);
local AStar = class("AStar");
function AStar:ctor(map)
    self.map = map;--地图
    self.openList = {};
    self.closeList = {};
    self.COST_STRAIGHT = 10;
    self.COST_DIAGONAL = 14;
    self.row = #self.map;--行
    self.column = #self.map[1];--列
end

--查找坐标（-1：错误，0：没找到，1：找到了）
function AStar:searchPatch(x1,y1,x2,y2)
    self.openList = {};
    self.closeList = {};
    if x1 < 1 or x1 > self.row or x2 < 1 or x2 > self.row or y1 < 1 or y1 > self.column or y2 < 1 or y2 > self.column then
        return -1;
    end
    if self.map[x1][y1] ~= 0 or self.map[x2][y2] ~= 0 then
        return -1;
    end
    local sGridNode = GridNode.new({x = x1,y = y1,par = nil});
    local eGridNode = GridNode.new({x = x2,y = y2,par = nil});
    table.insert(self.openList,sGridNode);
    local resultList = self:search(sGridNode,eGridNode);
    if #resultList == 0 then
        return 0;
    end
    return resultList;
end

function AStar:search(sNode,eNode)
    local resultList = {};
    local isFind = false;
    local tmpGridNode = nil;
    while #self.openList > 0 do
        --取出开启列表中最低F值，即第一个存储的值的F为最低的
        tmpGridNode = self.openList[1];
        if tmpGridNode:getX() == eNode:getX() and tmpGridNode:getY() == eNode:getY() then
            isFind = true;
            break;
        end
        --上
        if tmpGridNode:getY() - 1 >= 1 then
            self:checkPath(tmpGridNode:getX(),tmpGridNode:getY() - 1,tmpGridNode, eNode, self.COST_STRAIGHT);
        end
        --下
        if tmpGridNode:getY() + 1 <= self.column then
            self:checkPath(tmpGridNode:getX(),tmpGridNode:getY() + 1,tmpGridNode, eNode, self.COST_STRAIGHT);
        end
        --左
        if tmpGridNode:getX() - 1 >= 1 then
            self:checkPath(tmpGridNode:getX() - 1,tmpGridNode:getY(),tmpGridNode, eNode, self.COST_STRAIGHT);
        end
        --右
        if tmpGridNode:getX() + 1 <= self.row then
            self:checkPath(tmpGridNode:getX() + 1,tmpGridNode:getY(),tmpGridNode, eNode, self.COST_STRAIGHT);
        end
        --左上
        if tmpGridNode:getX() - 1 >= 1 and tmpGridNode:getY() - 1 >= 1 then
            self:checkPath(tmpGridNode:getX() - 1,tmpGridNode:getY() - 1,tmpGridNode, eNode, self.COST_DIAGONAL);
        end
        --左下
        if tmpGridNode:getX() - 1 >= 1 and tmpGridNode:getY() + 1 <= self.column then
            self:checkPath(tmpGridNode:getX() - 1,tmpGridNode:getY() + 1,tmpGridNode, eNode, self.COST_DIAGONAL);
        end
        --右上
        if tmpGridNode:getX() + 1 <= self.row and tmpGridNode:getY() - 1 >= 1 then
            self:checkPath(tmpGridNode:getX() + 1,tmpGridNode:getY() - 1,tmpGridNode, eNode, self.COST_DIAGONAL);
        end
        --右下
        if tmpGridNode:getX() + 1 <= self.row and tmpGridNode:getY() + 1 <= self.column then
            self:checkPath(tmpGridNode:getX() + 1,tmpGridNode:getY() + 1,tmpGridNode, eNode, self.COST_DIAGONAL);
        end
        --从开启列表中删除
        --添加到关闭列表中
        local del = self.openList[1];
        table.insert(self.closeList,del);
        table.remove(self.openList,1);
        --开启列表中排序，把F值最低的放到最底端
        table.sort(self.openList,function(a,b)
            return (a:getF() - b:getF()) < 0;
        end);
    end

    if isFind then
       self:getPath(resultList, tmpGridNode);
    end
    return resultList;
end

function AStar:checkPath(x,y,parNode,eNode,cost)
    local node = GridNode.new({x = x,y = y,par = parNode});
    if self.map[x][y] ~= 0 then
        table.insert(self.closeList,node);
        return false;
    end
    if self:isListContains(self.closeList,x,y) ~= -1 then
        return false;
    end
    local index = -1;
    index = self:isListContains(self.openList,x,y);
    if index ~= -1 then
        if parNode:getG() + cost < self.openList[index]:getG() then
            node.setParent(parNode);
            self:countG(node,eNode,cost);
            self:countF(node);
            self.openList[index] = node;
        end
    else
        node:setParent(parNode);
        self:count(node,eNode,cost);
        table.insert(self.openList,node);
    end
    return true;
end

function AStar:isListContains(list,x,y)
    for key, var in pairs(list) do
        if var:getX() == x and var:getY() == y then
            return key;
        end
    end
    return -1;
end

function AStar:getPath(list,node)
    if node:getParent() ~= nil then
        self:getPath(list,node:getParent());
    end
    table.insert(list,node);
end

function AStar:count(node,eNode,cost)
    self:countG(node,eNode,cost);
    self:countH(node,eNode);
    self:countF(node);
end
function AStar:countG(node,eNode,cost)
    if node:getParent() ==  nil then
        node:setG(cost);
    else
        node:setG(node:getParent():getG() + cost);
    end
end

function AStar:countH(node,eNode)
    node:setF(math.abs(node:getX() - eNode:getX()) + (math.abs(node:getY() - eNode:getY())) * 10);
end

function AStar:countF(node)
    node:setF(node:getG() + node:getH());
end

return AStar;


--endregion
